由我們主要用到的url_laucher及語言的部分可以看到若用合適的方式是可以使用packages的!
指令:flutter pub outdated
,由列出的選項可以看到,若找到合適安裝方式應是可以使用套件的
!
由圖所示,以Support表格來看是沒有問題的
等Dart基礎語法(到泛型為止)告一段落,就來支援研究套件安裝
由flutter的入口函數中我們可以看到myApp()
便會作為其入口函數
void main() => runApp(MyApp());
可選擇使用具名參數({param1, param2,...}
),但不強迫一定要傳送
void userSettings({int age, String name}){
//其中age與name便是可選參數,可以傳0(都不傳)~2(都傳)個參數皆可
}
用@require
作為前綴代表“必須傳入“的參數
void userSettings({@required int age,@required String name}){
//其中age與name此時便為必傳參數,兩者皆必須傳送
}
用[]
標記位置為可選的位置參數
void userSettings({int age,String name,[String interests]}){
if(interests != null){ //用if迴圈判斷可選參數的傳入值
print('興趣為 $interests');
}
}
可以用等號賦予預設的參數值,作為Compiling時的常數
void userSettings({int age = 21,String name = 'Xian'}){
//age預設為21,name預設為Xian
}
圖中便是將"printItem"函式作為參數使用
可以用var(創立變數的方式)來創立一個函數
官方Future class api,在非同步設計時,不會回傳尚未結束的計算結果,而是會傳其未來最終(Future)
會執行完的結果
參自:Future class
為了解決Callback Hell
的問題(如下圖所示)
發展出一種Syntactic Sugar
的方式,也就是async(需延遲的計算)
與await(延遲運算的佇列)
,以呼叫同步的過程來解決本問題
參自:Flutter---Google推出的跨平台框架,Android、iOS一起搞定 【Flutter基礎概念與實作】 Day5–Dart Language(3)
由下圖程式可以看到await被async所包裹(若沒有則會報錯),在Flutter網路請求的部分也會很常使用到本技巧,而往後還會延伸出isolate
與event loop
的概念!
//因非同步而引起的"Callback Hell"
step1('step1').then((step1Result){
step2(step1Result).then((step2Result){
step3(step2Result).then((step3Result){
//step4
//step5
//step6...
})
})
})
//用async與await的解法
steps() async{
String step1Result = await step1('step1');
String step2Result = await step2(step1Result);
String step3Result = await step3(step2Result);
//step4
//step5
//step6
}
Flutter屬於”單繼承“,且子類別可以由@overide
的方式來重新定義父類別。範例如下
首先在main()函式外我們定義兩個class:
class Computer{ //Computer內有三個子函式,play(),work(),search()
void play(){
print('Computer playing');
}
void work(){
print('Computer woking');
}
void search(){
print('Computer searching');
}
}
class Mac extends Computer{ //我們使用"Mac"繼承"Computer"
void play(){
super.play(); //調用Computer play的方式
print('Mac playing');
}
@override //覆蓋Computer 並繼承work的方式
void work(){
print('Mac work');
}
void Arc(){//在Mac裡獨立新增的函式,而Arc是一個新的瀏覽器,目前只有IOS版本QQ
print('Mac Arcing');
}
}
而在main()函式中我們呼叫兩式方式如下
void main() {
var newMac = Mac();//讓newMac變數為Mac()類別
var normalComputer = Computer();//讓normalComputer為Computer()類別
//分別呼叫各自子函式
newMac.play();
print('\n');//因為newMac.play()含有兩句話,用分行作為分割
newMac.work();
newMac.search();
normalComputer.search();
newMac.Arc();
}
輸出結果如下:
extends(繼承)小統整
extends
連接父與子類別,使其繼承(如圖中的"Mac"類別變繼承了"Computer"類別)super.[methodName]
,則會同時產生父類別的函式與子類別自行定義的(像是圖中的“Computer playing“與”Mac playing”)@override
則代表子類別可以使用父類別中同名的method來逕自做定義而不會改到父類別的定義(像圖中的"Mac working")!因為在dart中沒有interface(介面)等關鍵字,因此我們用A implements B
的方式表達"A實作B“的概念
範例:定義class如下
class Switch{ //開關具有開的功能
void turnOn(){
print('Turn on the switch');
}
}
class Light implements Switch{ //我們用"燈"來實現”開關的開功能“
@override
void turnOn(){
print('Turn on the light');
}
}
main()函式內呼叫
void main() {
var labLight = Light();
labLight.turnOn();
}
輸出結果
在「extneds(繼承)與implements(實現)在任一個class的數量皆只能有一個!」的前提下,便有了mixins(混合)
的概念,希望以A with B
,也就是「A在”非繼承於B的狀況下“,可以“重複”使用B中所實作的任一field或method」
範例:定義class如下
class Plants{
void Photosynthesis(){//光合作用
print('I can do photosynthesis');
}
}
class Animal{
void Breathe(){
print('I can breathe');
}
}
class Algae extends Animal with Plants{
//藻類屬於傳統類別中的動物界(真菌界和原核生物界)但具植物的特徵(使用with)
//可以看到用with後,大括號裡不需要再度定義規範
}
main()函式內呼叫如下
void main() {
var chlorophyta = Algae();//將綠藻定義為藻類
chlorophyta.Photosynthesis();//直接從Plants用"with"得到的Photosynthesis
chlorophyta.Breathe();//原本從Animal繼承的
}
輸出結果
extneds(繼承)
具有父子關係(也就是具有子包含於父
的集合關係)implements(實現)
則是對單一功能或需求的”實踐或套用“,兩者不一定會有包含關係(舉例而言,動物會呼吸,使用"呼吸"這個動作可以作為植物的implements,但植物並不能extends,也就是”繼承“動物)extneds(繼承)
與implements(實現)
在任一個class的數量皆只能有一個!
with
的混合方式就不用像implements需要再度定義extends
> with
> implements
我們希望以"泛型"達到下列兩個目的:
像是我們前幾日在看到List<E>
的方式便是一種泛型的樣態。
範例,我們以List<String>
限制本陣列只能存取字串的類型,若存入非字串元素則會報錯
void main() {
List animals = new List<String>(); //用List<String>的方式指定只能存取字串類型
animals.addAll(['小貓貓','小狗狗','小鳥鳥']);
}
報錯範例如圖,添加123(數字型態)進入animals中:
我們以下列程式碼作為比較,可以看到將兩類別(當中除型別外的規範皆相同)以泛型混合為Data後便只要寫一次就可以!
小補充:<T>
也可以將中間換做E,S,K
等,我們以單一大寫英文字母作為型別引數
//1. 不用泛型的範例
abstract class ObjectData{ //Objsct形態的Data
Object getByKey(String key);
void setByKey(String key, Object value);
}
abstract class StringData{ //String形態的Data
String getByKey(String key);
void setByKey(String key, String value);
}
//2. 使用泛型修改後的範例
abstract class Data<T>{
//可以看到我們將getByKey與setByKey中的value參數的類型改為T
T getByKey(String key);
void setByKey(String key, T value);
}
我們也可以透過extends
來限制參數類型
class Animal {}
class Cat extends Animal {} //Cat繼承Animal
class Bird extends Animal {} //Bird繼承Animal
class NewAnimal<T extends Animal> {
String toString() => "建立一個新的小動物:'Foo<$T>'";//Foo<$T>作為泛型接口
}
void main() {
var cat = NewAnimal<Cat>();
var bird = NewAnimal<Bird>();
var animal = NewAnimal(); //沒有指定動物,維持原本extends的Animal
print(cat);
print(bird);
print(animal);
}
Class/Field/Constructor
相關的知識也可以看這裡!